from flask import Flask, render_template_string, request
import requests
import time
from datetime import timedelta


# =====================
# Prometheus Client
# =====================
class PrometheusClient:
    def __init__(self, base_url: str, timeout: int = 10):
        self.base_url = base_url.rstrip("/")
        self.session = requests.Session()
        self.timeout = timeout

    def query(self, query: str):
        try:
            resp = self.session.get(
                f"{self.base_url}/api/v1/query",
                params={"query": query},
                timeout=self.timeout
            )
            resp.raise_for_status()
            data = resp.json()
            return data.get("data", {}).get("result", []) if data.get("status") == "success" else []
        except Exception as e:
            print(f"[查询失败] {e} | query={query}")
            return []


# =====================
# Helper Functions
# =====================
def clean_image_name(image: str) -> str:
    """清理镜像名称，去除指定的前缀"""
    prefixes_to_remove = [
        "ksher-ccr.tencentcloudcr.com/ksher-prod/",
        "test-ksher-ccr.tencentcloudcr.com/ksher-uat/"
    ]

    for prefix in prefixes_to_remove:
        if image.startswith(prefix):
            return image[len(prefix):]

    return image


# =====================
# Data Functions
# =====================
def get_deployments_from_prod(prom: PrometheusClient, namespace: str = "ksher"):
    """从生产环境获取所有deployment名称"""
    queries = [
        f'kube_deployment_metadata{{namespace="{namespace}"}}',
        f'kube_deployment_status_replicas{{namespace="{namespace}"}}'
    ]
    deployments = {
        item.get("metric", {}).get("deployment", "")
        for q in queries
        for item in prom.query(q)
    }
    return sorted(filter(None, deployments))


def get_images_from_env(prom: PrometheusClient, deployment: str, namespace: str):
    """从指定环境和命名空间获取deployment的镜像，并清理镜像名称"""
    # 首先尝试通过deployment查询
    images = {
        item.get("metric", {}).get("image")
        for item in prom.query(f'kube_deployment_container_image{{namespace="{namespace}", deployment="{deployment}"}}')
        if "image" in item.get("metric", {})
    }

    # 如果没有找到，尝试通过pod查询
    if not images:
        images = {
            item.get("metric", {}).get("image")
            for item in prom.query(f'kube_pod_container_info{{namespace="{namespace}", pod=~"{deployment}-.*"}}')
            if "image" in item.get("metric", {})
        }

    # 清理镜像名称
    cleaned_images = [clean_image_name(img) for img in images] if images else ["Not Found"]
    return sorted(cleaned_images)


def get_images_from_uat(prom: PrometheusClient, deployment: str):
    """从UAT环境获取镜像，按优先级查询多个命名空间"""
    search_path = [
        # 第一优先级：uat-ksher命名空间，原名称
        {"namespace": "uat-ksher", "deployment": deployment, "suffix": ""},
        # 第二优先级：uat-ksher命名空间，加-uat后缀
        {"namespace": "uat-ksher", "deployment": f"{deployment}-uat", "suffix": "-uat"},
        # 第三优先级：uat-ksher-py命名空间，原名称
        {"namespace": "uat-ksher-py", "deployment": deployment, "suffix": ""},
        # 第四优先级：uat-ksher-py命名空间，加-uat后缀
        {"namespace": "uat-ksher-py", "deployment": f"{deployment}-uat", "suffix": "-uat"},
    ]

    for search in search_path:
        images = get_images_from_env(prom, search["deployment"], search["namespace"])
        if images != ["Not Found"]:
            return images, search["deployment"], search["namespace"], search["suffix"]

    # 所有搜索路径都没找到
    return ["Not Found"], deployment, "Not Found", ""


# =====================
# Flask App
# =====================
app = Flask(__name__)
PROMETHEUS_URLS = {
    "216": "http://10.10.7.216:9090",
    "prod": "http://prod-prometheus.ksherpay.com"
}

PROD_NAMESPACE = "ksher"
UAT_NAMESPACES = ["uat-ksher", "uat-ksher-py"]

HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>生产与UAT环境镜像对比</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .env-diff {
            background-color: #fff3cd !important;
        }
        .not-found {
            background-color: #f8d7da !important;
        }
        .table th {
            background-color: #f8f9fa;
            position: sticky;
            top: 0;
        }
        .badge-uat {
            background-color: #6c757d;
        }
        .badge-namespace-ksher {
            background-color: #17a2b8;
        }
        .badge-namespace-py {
            background-color: #6f42c1;
        }
        .table-container {
            max-height: 80vh;
            overflow-y: auto;
        }
        .search-path {
            font-size: 0.9em;
            color: #6c757d;
        }
        .filter-section {
            background-color: #f8f9fa;
            border-radius: 5px;
            padding: 15px;
            margin-bottom: 20px;
        }
        .filter-active {
            font-weight: bold;
            color: #0d6efd !important;
        }
        .table-responsive {
            overflow-x: auto;
        }
        #searchInput {
            max-width: 300px;
        }
    </style>
</head>
<body class="p-4">
    <div class="container">
        <h2 class="mb-4">生产环境 vs UAT环境 镜像对比</h2>

        <!-- 搜索和过滤区域 -->
        <div class="filter-section mb-4">
            <div class="row align-items-center">
                <div class="col-md-6">
                    <div class="input-group mb-2">
                        <span class="input-group-text">搜索</span>
                        <input type="text" id="searchInput" class="form-control" placeholder="输入Deployment名称..." 
                               value="{{ search_query if search_query else '' }}">
                        <button class="btn btn-outline-secondary" type="button" onclick="clearSearch()">清除</button>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="d-flex flex-wrap align-items-center">
                        <span class="me-2">镜像状态过滤:</span>
                        <div class="btn-group btn-group-sm" role="group">
                            <a href="{{ url_for('index', status='all', search=search_query) }}" 
                               class="btn btn-outline-primary {{ 'filter-active' if status_filter == 'all' else '' }}">全部</a>
                            <a href="{{ url_for('index', status='match', search=search_query) }}" 
                               class="btn btn-outline-success {{ 'filter-active' if status_filter == 'match' else '' }}">一致</a>
                            <a href="{{ url_for('index', status='diff', search=search_query) }}" 
                               class="btn btn-outline-warning {{ 'filter-active' if status_filter == 'diff' else '' }}">不一致</a>
                            <a href="{{ url_for('index', status='not_found', search=search_query) }}" 
                               class="btn btn-outline-danger {{ 'filter-active' if status_filter == 'not_found' else '' }}">未找到</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        {% if data %}
        <div class="table-responsive table-container">
            <table class="table table-bordered table-hover">
                <thead class="table-dark" style="position: sticky; top: 0; z-index: 1;">
                    <tr>
                        <th style="color: black;">Deployment 名称</th>
                        <th style="color: black;">生产环境镜像<br><span class="badge badge-namespace-ksher">ksher</span></th>
                        <th style="color: black;">UAT环境镜像</th>
                        <th style="color: black;">镜像状态</th>
                    </tr>
                </thead>
                <tbody>
                    {% for d in data %}
                    <tr class="{{ 'env-diff' if d.status == 'diff' else 'not-found' if d.status == 'not_found' else '' }}">
                        <td><strong>{{ d.name }}</strong></td>
                        <td>{{ d.images_prod }}</td>
                        <td>{{ d.images_uat }}</td>
                        <td>
                            {% if d.status == 'match' %}
                                <span class="badge bg-success">一致</span>
                            {% elif d.status == 'diff' %}
                                <span class="badge bg-warning text-dark">不一致</span>
                            {% else %}
                                <span class="badge bg-danger">未找到</span>
                            {% endif %}
                        </td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
        {% else %}
        <p class="text-danger">未找到任何 deployment。</p>
        {% endif %}

        <div class="mt-4 p-3 bg-light rounded">
            <div class="row">
                <div class="col-md-4">
                    <strong>环境信息：</strong><br>
                    • 生产: {{ PROMETHEUS_URLS.prod }} ({{ PROD_NAMESPACE }})<br>
                    • UAT: {{ PROMETHEUS_URLS.216 }}
                </div>
                <div class="col-md-4">
                    <strong>连接状态：</strong><br>
                    • 生产: <span class="badge bg-{{ 'success' if prom_prod_status == '连接正常' else 'danger' }}">{{ prom_prod_status }}</span><br>
                    • UAT: <span class="badge bg-{{ 'success' if prom_216_status == '连接正常' else 'danger' }}">{{ prom_216_status }}</span>
                </div>
                <div class="col-md-4">
                    <strong>统计信息：</strong><br>
                    总计: {{ total_count }} 个<br>
                    一致: <span class="text-success">{{ match_count }}</span> |
                    不一致: <span class="text-warning">{{ diff_count }}</span> |
                    未找到: <span class="text-danger">{{ not_found_count }}</span>
                </div>
            </div>
            <div class="mt-2 text-muted">
                最后更新时间: {{ update_time }}
            </div>
        </div>
    </div>

    <script>
        // 搜索功能
        document.getElementById('searchInput').addEventListener('keyup', function() {
            const searchValue = this.value.toLowerCase();
            const rows = document.querySelectorAll('tbody tr');

            rows.forEach(row => {
                const deploymentName = row.querySelector('td:first-child strong').textContent.toLowerCase();
                if (deploymentName.includes(searchValue)) {
                    row.style.display = '';
                } else {
                    row.style.display = 'none';
                }
            });
        });

        // 清除搜索
        function clearSearch() {
            document.getElementById('searchInput').value = '';
            const rows = document.querySelectorAll('tbody tr');
            rows.forEach(row => {
                row.style.display = '';
            });
        }

        // 如果URL中有搜索参数，自动填充搜索框
        window.addEventListener('load', function() {
            const urlParams = new URLSearchParams(window.location.search);
            const searchParam = urlParams.get('search');
            if (searchParam) {
                document.getElementById('searchInput').value = searchParam;
                // 触发搜索
                const event = new Event('keyup');
                document.getElementById('searchInput').dispatchEvent(event);
            }
        });
    </script>
</body>
</html>
"""


def compare_images(images1, images2):
    """比较两个镜像列表是否相同"""
    return set(images1) == set(images2)


def get_search_priority(namespace, suffix):
    """获取搜索路径的优先级描述"""
    priorities = {
        ("uat-ksher", ""): "1. uat-ksher (原名称)",
        ("uat-ksher", "-uat"): "2. uat-ksher (+uat)",
        ("uat-ksher-py", ""): "3. uat-ksher-py (原名称)",
        ("uat-ksher-py", "-uat"): "4. uat-ksher-py (+uat)",
    }
    return priorities.get((namespace, suffix), "未知路径")


@app.route("/")
def index():
    # 获取查询参数
    status_filter = request.args.get('status', 'all')
    search_query = request.args.get('search', '')

    # 创建两个环境的客户端
    clients = {
        "216": PrometheusClient(PROMETHEUS_URLS["216"]),
        "prod": PrometheusClient(PROMETHEUS_URLS["prod"])
    }

    # 检查连接状态
    status = {}
    for env, client in clients.items():
        try:
            # 简单的查询来测试连接
            test_query = 'up'
            result = client.query(test_query)
            status[env] = "连接正常" if result is not None else "连接异常"
        except Exception as e:
            status[env] = f"连接异常: {str(e)}"

    # 从生产环境获取deployment列表
    deployments = get_deployments_from_prod(clients["prod"], PROD_NAMESPACE)

    data = []
    match_count = 0
    diff_count = 0
    not_found_count = 0

    for dep in deployments:
        # 获取生产环境镜像
        images_prod = get_images_from_env(clients["prod"], dep, PROD_NAMESPACE)

        # 获取UAT环境镜像（按照优先级查询多个命名空间）
        images_uat, actual_deployment, uat_namespace, used_suffix = get_images_from_uat(clients["216"], dep)

        # 确定状态
        if images_uat == ["Not Found"]:
            status_flag = "not_found"
            not_found_count += 1
        elif compare_images(images_prod, images_uat):
            status_flag = "match"
            match_count += 1
        else:
            status_flag = "diff"
            diff_count += 1

        data.append({
            "name": dep,
            "images_prod": "; ".join(images_prod),
            "images_uat": "; ".join(images_uat),
            "status": status_flag
        })

    # 按状态排序：未找到 > 不一致 > 一致
    status_order = {"not_found": 0, "diff": 1, "match": 2}
    data.sort(key=lambda x: status_order[x["status"]])

    # 应用搜索过滤
    if search_query:
        data = [d for d in data if search_query.lower() in d["name"].lower()]

    # 应用状态过滤
    if status_filter != 'all':
        data = [d for d in data if d["status"] == status_filter]

    return render_template_string(
        HTML_TEMPLATE,
        data=data,
        namespace=PROD_NAMESPACE,
        update_time=time.strftime("%Y-%m-%d %H:%M:%S"),
        prom_216_status=status["216"],
        prom_prod_status=status["prod"],
        total_count=len(data),
        match_count=match_count,
        diff_count=diff_count,
        not_found_count=not_found_count,
        PROMETHEUS_URLS={
            "prod": PROMETHEUS_URLS["prod"],
            "216": PROMETHEUS_URLS["216"]
        },
        PROD_NAMESPACE=PROD_NAMESPACE,
        status_filter=status_filter,
        search_query=search_query
    )


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5003, debug=True)